package com.caisejingyu.whales.home.devices.printer;

import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.text.TextUtils;
import android.util.Size;
import android.util.SizeF;

import java.math.BigDecimal;

/**
 * Created by fengxing on 2017/2/22.
 */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public abstract class AbsImageProcessor implements IPrintExcute {
    protected static final int DPI = 300;
    protected int mOffsetPx;
    protected float mOffset;
    protected String mShellStr = "/system/cups/bin/lp -o scale=100 -o orientation-requested=3 -o media=Custom.%.1fx%.1fcm ";

    protected int dpi(float mm) {
        return (int) (mm * DPI / 2.54);
    }

    protected float px2Cm(int px) {
        double cm = px * 2.54 / DPI;
        BigDecimal b = new BigDecimal(cm);
        return b.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    protected Size dpi(SizeF size) {
        return new Size(dpi(size.getWidth()), dpi(size.getHeight()));
    }

    protected Rect dpi(RectF rect) {
        return new Rect(dpi(rect.left),
                dpi(rect.top),
                dpi(rect.right),
                dpi(rect.bottom));
    }

    @Override
    public void setHorizontalOffset(int offset) {
        this.mOffsetPx = offset;
        this.mOffset = px2Cm(offset);
    }

    @Override
    public boolean exec(String photo, String rahmen, String adi) {
        String print = process(photo, rahmen, adi);
        if (print == null)
            return false;
        String exec = shellExec(print);
        if (!TextUtils.isEmpty(exec) && exec.contains("request")) {
            return true;
        } else {
            return false;
        }
    }

    protected String format(float width, float height) {
        return String.format(mShellStr, width, height);
    }

    protected abstract String shellExec(String print);

    protected abstract String process(String file, String rahmen, String advise);

    protected void drawRahmen(String rahmen, Canvas canvas, Rect target, Paint paint) {
        if (!TextUtils.isEmpty(rahmen)) {
            Bitmap frame = null;
            try {
                frame = BitmapFactory.decodeFile(rahmen);
                canvas.drawBitmap(frame, new Rect(0, 0,
                        frame.getWidth(), frame.getHeight()), target, paint);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (frame != null) {
                    frame.recycle();
                }
            }

        }
    }

    protected Rect selectPhotoRange(Size photo, SizeF context) {
        Rect select = new Rect();
        final float photoRadius = div(photo.getHeight(), photo.getWidth());
        final float contextRadius = div(context.getHeight(), context.getWidth());
        if (photoRadius > contextRadius) {
            //all width
            select.left = 0;
            select.right = (int) photo.getWidth();
            //padding*2=kickout
            final float mul = mul(photo.getWidth(), contextRadius);
            int kick = (int) (sub(photo.getHeight(), mul) / 2);
            select.top = kick;
            select.bottom = photo.getHeight() - kick;

        } else {
            //all hiehgt
            select.top = 0;
            select.bottom = photo.getHeight();
            //padding*2=kickout
            final float mul = mul(photo.getHeight(), div(context.getWidth(), context.getHeight()));
            int kick = (int) sub(photo.getWidth(), mul) / 2;
            select.left = kick;
            select.right = photo.getWidth() - kick;
        }
        return select;
    }

    /**
     * 通过类似CenterCrop的方式计算出画布的大小
     * 计算方式是 -->
     * 1、首先根据图像的大小和图像在相纸中的比例，计算（CenterCrop）出画布的大小
     * 2、然后根据图像在相纸的比例以及计算的画布大小计算出完整的画布大小
     * <p>
     * 因为相纸中可能打印相片+广告，所以通过第一步计算出来的画布可能没有包含广告的大小
     * 所以需要通过第二步，根据图像在相纸的比例再次重新计算一下完整的画布大小
     * <p>
     * 之前的版本是固定画布的大小，根据#{@link AbsImageProcessor#dpi(float)}直接计算出画布的大小
     * 现在是根据图片的大小来计算出画布的大小，这样可以通过打印机来自动缩放图片的大小，而我们只需要指定输出相纸大小即可
     *
     * @param photo   图片大小
     * @param context 图像在相纸中的大小
     * @param pager   相纸大小
     * @return
     */
    protected Rect calCanvasSize(Size photo, SizeF context, SizeF pager) {
        final Rect rect = selectPhotoRange(photo, context);

        final Rect result = new Rect();
        result.left = 0;
        result.top = 0;
        result.right = rect.width();
        result.bottom = (int) Math.ceil(rect.height() * pager.getHeight() / context.getHeight());
        return result;
    }

    /**
     * 换算偏移量的大小
     * 之前固定画布大小，为了兼容之前的数据，所以按照比例换算成现在的大小
     *
     * @param src         原画布大小
     * @param target      现在画布的大小
     * @param translation 原来的偏移量
     * @return
     */
    protected int convertTranslate(int src, int target, int translation) {
        return (int) Math.ceil(mul(translation, div(target, src)));
    }

    /**
     * 通过在相纸中的大小来换算画布中的大小
     *
     * @param target 目标在相纸中的大小
     * @param paper  相纸大小
     * @param rect   画布大小
     * @param isTop  是否是顶部区域
     * @return
     */
    protected Rect calTargetSize(float target, float paper, Rect rect, boolean isTop) {
        final Rect result = new Rect();
        result.left = 0;
        result.right = rect.width();
        if (isTop) {
            result.top = 0;
            result.bottom = (int) Math.ceil(target / paper * rect.height());
        } else {
            result.top = rect.height() - (int) (target / paper * rect.height());
            result.bottom = rect.height();
        }

        return result;
    }

    //相加
    protected float add(float d1, float d2) {
        BigDecimal b1 = new BigDecimal(Float.toString(d1));
        BigDecimal b2 = new BigDecimal(Float.toString(d2));
        return b1.add(b2).floatValue();
    }

    //相减
    protected float sub(float d1, float d2) {
        BigDecimal b1 = new BigDecimal(Float.toString(d1));
        BigDecimal b2 = new BigDecimal(Float.toString(d2));
        return b1.subtract(b2).floatValue();
    }

    //相乘
    protected float mul(float d1, float d2) {
        BigDecimal b1 = new BigDecimal(Float.toString(d1));
        BigDecimal b2 = new BigDecimal(Float.toString(d2));
        return b1.multiply(b2).floatValue();
    }

    //相除
    protected float div(float d1, float d2) {
        return div(d1, d2, 10);
    }

    protected float div(float d1, float d2, int scale) {
        if (scale < 0) {
            scale = 1;
        }
        BigDecimal b1 = new BigDecimal(Float.toString(d1));
        BigDecimal b2 = new BigDecimal(Float.toString(d2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).floatValue();
    }
}
